home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
os2
/
pmnos11s
/
lpdfilt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-30
|
14KB
|
613 lines
/* Internet LPD Server filters
* written by David Johnson (dave@cs.olemiss.edu)
*
* This code is in the public domain.
*
* Revision History:
*
* Revision 1.4 91/09/25 dave
* Changed subtraction of integer 1 to character '1' in wait_for_printer()
*
* Revision 1.3 91/09/19 dave
* Handle output processing for expanding tabs
*
* Revision 1.2 91/09/17 dave
* Handle output processing for each device, not just internal
*
* Revision 1.1 91/09/14 dave (from marko winblad)
* Correction to definition of variable 'c' in input_char() to int.
*
* Revision 1.0 91/09/04 dave
* Initial Release
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <dos.h>
#ifdef __TURBOC__
#include <io.h>
#include <dir.h>
#endif
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "asy.h"
#include "socket.h"
#include "dirutil.h"
#include "commands.h"
#include "files.h"
#include "lp.h"
#include "lpd.h"
#include "lpdfilt.h"
/*
* All filters which are supported are prototyped in lpdfilt.h
*/
/* local functions - public */
void output_char __ARGS((struct filter_stream *io_stream, int c));
void output_string __ARGS((struct filter_stream *io_stream, char *s));
void stream_flush __ARGS((struct filter_stream *io_stream));
/* local functions - private */
static void stream_setup __ARGS((struct filter_stream *io_stream));
static int input_char __ARGS((struct filter_stream *io_stream));
struct LPDfilter filter_list[] = {
{"text", text_filter}, /* generic IF filter */
{"ps_switch", ps_switch_filter}, /* postscript or */
/* text auto-switch */
{"text_ps", text_ps_filter}, /* postscript or */
/* text to postscript */
{ NULL, NULLVFP}
};
/*
* Wait for printer to be available.
* Only called for DOS devices (LPT1-3, COM1-4).
*/
static int
wait_for_printer( device )
struct LPDdevice *device;
{
union REGS regs;
#define NOT_BUSY 0x80
#define ACK 0x40
#define OUT_OF_PAPER 0x20
#define SELECTED 0x10
#define IO_ERROR 0x08
if( *device->name == 'L' ) { /* LPT? */
for(;;) {
regs.h.ah = 2; /* READ STATUS */
regs.x.dx = *(device->name + 3) - '1'; /* 0-2 */
int86( 0x17, ®s, ®s );
if( (regs.h.ah & (NOT_BUSY|SELECTED))
== (NOT_BUSY|SELECTED) )
break;
YIELD;
}
} else if( *device->name == 'C' ) { /* COM? */
/* This needs more work...what are the status values
* returned?
*/
for(;;) {
regs.h.ah = 3; /* READ STATUS */
regs.x.dx = *(device->name + 3) - '1'; /* 0-3 */
int86( 0x14, ®s, ®s );
if( (regs.h.ah & 0x60) != 0 )
break;
YIELD;
}
}
}
/*
* Filter "stream" I/O routines.
*/
static void
stream_setup( io_stream )
struct filter_stream *io_stream;
{
if( io_stream->type == IO_SOCKET ) {
sockmode( io_stream->stream.socket, SOCK_ASCII );
sockowner( io_stream->stream.socket, Curproc );
}
}
void
output_char( io_stream, c )
struct filter_stream *io_stream;
int c;
{
struct mbuf *bp;
switch( io_stream->type ) {
case IO_SOCKET:
usputc( io_stream->stream.socket, c );
break;
case IO_FILE:
wait_for_printer( io_stream->device );
putc( c, io_stream->stream.fp );
break;
case IO_LOCAL:
bp = pushdown(NULLBUF, 1);
bp->data[0] = c;
asy_send( (io_stream->stream.ifp)->dev, bp );
(io_stream->stream.ifp)->lastsent = secclock();
break;
}
}
static int
input_char( io_stream )
struct filter_stream *io_stream;
{
int c;
switch( io_stream->type ) {
case IO_SOCKET:
c = recvchar( io_stream->stream.socket );
break;
case IO_FILE:
c = getc( io_stream->stream.fp );
break;
case IO_LOCAL:
c = get_asy((io_stream->stream.ifp)->dev);
break;
}
return c;
}
void
output_string( io_stream, s )
struct filter_stream *io_stream;
char *s;
{
struct mbuf *bp;
switch( io_stream->type ) {
case IO_SOCKET:
usputs( io_stream->stream.socket, s );
break;
case IO_FILE:
wait_for_printer( io_stream->device );
fputs( s, io_stream->stream.fp );
break;
case IO_LOCAL:
bp = pushdown(NULLBUF, strlen(s));
strcpy( bp->data, s );
asy_send( (io_stream->stream.ifp)->dev, bp );
(io_stream->stream.ifp)->lastsent = secclock();
break;
}
}
void
stream_flush( io_stream )
struct filter_stream *io_stream;
{
if( io_stream->type == IO_FILE )
fflush( io_stream->stream.fp );
else if( io_stream->type == IO_SOCKET )
usflush( io_stream->stream.socket );
}
/*
* Write accounting information to accounting file
* Adapted from PLP
*/
static void
write_to_af( parms, pages )
struct filter_parms *parms;
int pages;
{
time_t current_time;
FILE *fp;
(void)time( ¤t_time );
if( parms->af_file && access( parms->af_file, 02 ) >= 0 ) {
if( (fp = fopen( parms->af_file, "a" )) != NULL ) {
fprintf( fp, "%s\t%s\t%s\t%7d\t%c\t%s",
parms->login_name ? parms->login_name : "NULL",
parms->host ? parms->host : "NULL",
parms->printer_name ? parms->printer_name : "NULL",
pages,
parms->format,
ctime( ¤t_time ) );
fclose( fp );
}
}
YIELD;
}
/*
* FILTER RULES:
* All filters which do no network I/O must give up processing after
* short intervals of printing using YIELD. NOS does not implement
* pre-emptive scheduling and therefore other network activity will
* be paused while printing.
*/
/*
* Standard text filter.
*/
void
text_filter( unused, vparms, unused2 )
int unused;
void *vparms;
void *unused2;
{
struct filter_parms *parms;
int c, i, x;
int nchars = 0, nlines = 0, npages;
char *indent_string;
parms = (struct filter_parms *)vparms;
npages = parms->pages; /* count banner page */
#ifdef LPD_DEBUG
tprintf( "text_filter( %p, %p, %c )\n", parms, parms->sync, parms->format );
tprintf( "input = %d, output = %d\n", parms->input.type, parms->output.type );
tflush();
#endif
if( parms->indent ) {
/* build indent string */
indent_string = malloc( parms->indent+1 );
for( i = 0; i < parms->indent; i++ )
indent_string[i] = ' ';
indent_string[i] = NULL;
/* indent first line */
output_string( &parms->output, indent_string );
}
for( ;; ) {
c = input_char( &parms->input );
if( c == EOF ) {
break;
} else if( parms->literal ) {
output_char( &parms->output, c );
if( ++nchars > 128 ) {
nchars = 0;
YIELD;
}
} else if( c == '\n' || c == '\r' ) {
if( c == '\n' && (parms->output.device->flags & CRMOD ) )
output_char( &parms->output, '\r' );
nchars = 0;
output_char( &parms->output, c );
if( ++nlines > parms->length ) {
nlines = 0;
npages++;
}
if( parms->indent )
output_string( &parms->output, indent_string );
YIELD;
} else if( c == '\f' ) {
nchars = 0;
nlines = 0;
npages++;
output_char( &parms->output, c );
if( parms->indent )
output_string( &parms->output, indent_string );
YIELD;
} else if( c == '\b' ) {
if( --nchars < 0 )
nchars = 0;
output_char( &parms->output, c );
} else if( c == '\t' ) {
if( parms->output.device->flags & XTABS ) {
x = 8 - ((nchars + 8) % 8);
if( nchars + x < parms->width )
while( x-- > 0 )
output_char( &parms->output, ' ' );
}
} else if( ++nchars < parms->width )
output_char( &parms->output, c );
}
if( !parms->literal ) {
if( nchars > 0 ) {
output_char( &parms->output, '\r' );
output_char( &parms->output, '\n' );
nlines++;
}
if( nlines > 0 ) {
output_char( &parms->output, '\f' );
npages++;
}
}
stream_flush( &parms->output );
YIELD;
if( parms->indent )
free( indent_string );
write_to_af( parms, npages );
if( parms->sync ) /* TRUE if not called from ps_text */
psignal( parms->sync, 0 );
}
/*
* encapsulated-postscript/regular text auto-switch filter.
*
* If file starts with '%!' the file must be PostScript.
* Use the ps_start, ps_end, and default_ps parameters as appropriate to
* place the printer in the correct mode.
*
* Otherwise, send the file through the default text_filter.
*
* BUGS: must be fed a file, if fed a stream, the first two characters
* of a non-PostScript stream will be lost.
*/
void
ps_switch_filter( unused, vparms, unused2 )
int unused;
void *vparms;
void *unused2;
{
struct filter_parms *parms;
int c;
int *sync, postscript;
char *start, *end;
parms = (struct filter_parms *)vparms;
#ifdef LPD_DEBUG
tprintf( "ps_switch_filter( %c )\n", parms->format );
tflush();
#endif
postscript = 0;
start = end = NULL;
if( parms->format != 'p' ) {
/*
* See if file is encapsulated-postscript
*/
c = input_char( &parms->input );
if( c == '%' ) { /* maybe */
c = input_char( &parms->input );
if( c == '!' ) { /* YES! */
postscript = 1;
if( !parms->default_ps ) {
start = parms->ps_start;
end = parms->ps_end;
}
}
}
rewind( parms->input.stream.fp );
}
YIELD;
if( !postscript ) {
if( parms->default_ps ) {
start = parms->ps_end;
end = parms->ps_start;
}
}
/*
* Place the printer in Standard Text or PostScript mode as
* appropriate.
*/
if( start )
output_string( &parms->output, start );
/*
* save sync address so that text_filter will not signal our
* parent since output may not be complete.
*/
sync = parms->sync;
parms->sync = 0;
/*
* call the standard text_filter.
*/
if( postscript ) /* PostScript files must be literal */
parms->literal = 1;
text_filter( unused, vparms, unused2 );
YIELD;
/*
* Place the printer back into the default mode.
*/
if( end )
output_string( &parms->output, end );
/*
* signal our parent
*/
psignal( sync, 0 );
}
/*
* encapsulated-postscript/regular text to postscript filter.
*
* If file starts with '%!' the file must be PostScript.
* Send file directly to printer.
*
* Otherwise, send the text-to-postscript leader file '/etc/lpt.ps'
* followed by the text file.
*
* BUGS: must be fed a file, if fed a stream, the first two characters
* of a non-PostScript stream will be lost.
*/
void
text_ps_filter( unused, vparms, unused2 )
int unused;
void *vparms;
void *unused2;
{
struct filter_parms *parms;
int c;
int *sync, postscript;
FILE *leader_fp, *original_fp;
struct filter_stream original_file;
parms = (struct filter_parms *)vparms;
#ifdef LPD_DEBUG
tprintf( "text_ps_filter( %c )\n", parms->format );
tflush();
#endif
postscript = 0;
if( parms->format != 'p' ) {
/*
* See if file is encapsulated-postscript
*/
c = input_char( &parms->input );
if( c == '%' ) { /* maybe */
c = input_char( &parms->input );
if( c == '!' ) /* YES! */
postscript = 1;
}
rewind( parms->input.stream.fp );
}
YIELD;
/*
* save sync address so that text_filter will not signal our
* parent since output may not be complete.
*/
sync = parms->sync;
parms->sync = 0;
if( !postscript ) {
/*
* First, the text-to-postscript leader file must be
* sent to the printer.
*/
original_file = parms->input; /* save for later */
if( (leader_fp = fopen( "/etc/lpt.ps", "r" )) != NULL ) {
parms->input.stream.fp = leader_fp;
parms->input.type = IO_FILE;
parms->literal = 1;
/*
* Now, send the leader through the text_filter.
*/
text_filter( unused, vparms, unused2 );
YIELD;
}
parms->input = original_file; /* restore */
}
/*
* call the standard text_filter. Both file types must now be literal.
*/
parms->literal = 1;
text_filter( unused, vparms, unused2 );
YIELD;
/*
* signal our parent
*/
psignal( sync, 0 );
}
/*
* Format the input file as UNIX pr(1) and send output to socket which
* should be "piped" to the corresponding IF filter.
*/
void
pr_filter( unused, vparms, unused2 )
int unused;
void *vparms;
void *unused2;
{
struct pr_parms *parms;
int line_count, i;
char buffer[512];
char page_string[5], *time_string;
int page_number, text_lines, page_length;
time_t current_time;
parms = (struct pr_parms *)vparms;
#ifdef LPD_DEBUG
tputs( "pr_filter()\n" );
tflush();
#endif
sockmode( parms->out_s, SOCK_ASCII );
sockowner( parms->out_s, Curproc ); /* We own it now */
page_number = 1;
text_lines = parms->length - PR_TOP_MARGIN - PR_BOTTOM_MARGIN;
(void) time( ¤t_time );
time_string = ctime( ¤t_time );
rip( time_string );
if( fgets( buffer, 510, parms->file_fp ) == NULL )
goto EXIT;
for( ;; ) {
line_count = 1;
for( i = 0; i < PR_TOP_MARGIN/2; i++ )
usputc( parms->out_s, '\n' );
usputs( parms->out_s, time_string );
usputs( parms->out_s, " " );
usputs( parms->out_s, parms->title );
usputs( parms->out_s, " Page " );
sprintf( page_string, "%d\n", page_number);
usputs( parms->out_s, page_string );
for( i = 0; i < PR_TOP_MARGIN/2; i++ )
usputc( parms->out_s, '\n' );
while( line_count <= text_lines ) {
line_count++;
if( *buffer == '\f' ) {
usputc( parms->out_s, '\n' );
} else {
usputs( parms->out_s, buffer );
if( fgets( buffer, 510, parms->file_fp ) == NULL )
goto EXIT;
}
}
if( *buffer == '\f' ) {
if( fgets( buffer, 510, parms->file_fp ) == NULL )
goto EXIT;
}
/* bottom margin */
for( i = 0; i < PR_BOTTOM_MARGIN; i++ )
usputc( parms->out_s, '\n' );
page_number++;
}
EXIT: /* finish last page */
usputc( parms->out_s, '\f' );
close_s( parms->out_s );
}